using System;
using System.Collections.Generic;

namespace AutoChess
{
    public class ActorActionAttribute
    {
        private class AttrChangeHandler
        {
            public Delegate m_handle;

            public void AddDelegate(Delegate handler)
            {
                m_handle = Delegate.Combine(m_handle, handler);
            }

            public void RmvDelegate(Delegate handler)
            {
                m_handle = Delegate.Remove(m_handle, handler);
            }
        }
        
        private Dictionary<int,object> m_dictAttr = new Dictionary<int, object>();
        private Dictionary<int,AttrChangeHandler> m_attrChangedListener = new Dictionary<int, AttrChangeHandler>();

        public void SetAttribute<T>(ActorActionAttrDef actionAttrId, T val)
        {
            SetAttribute((int)actionAttrId,val);
        }

        public void SetAttribute<T>(int attrId, T val)
        {
            bool changed = false;

            T existVal;
            object exist;
            if (m_dictAttr.TryGetValue(attrId, out exist))
            {
                existVal = (T) exist;

                if ((exist == null && val != null) || !exist.Equals(val))
                {
                    changed = true;
                }
            }
            else
            {
                existVal = default(T);
                changed = true;
            }

            if (changed)
            {
                m_dictAttr[attrId] = val;

                AttrChangeHandler handler;
                if (m_attrChangedListener.TryGetValue(attrId, out handler))
                {
                    Action<T, T> deleHandle = handler.m_handle as Action<T, T>;
                    if (deleHandle != null)
                    {
                        deleHandle(existVal, val);
                    }

                }
            }
        }

        public T GetAtrribute<T>(ActorActionAttrDef actionAttrId)
        {
            T val;
            TryGetAttribute(actionAttrId, out val);
            return val;
        }

        public bool TryGetAttribute<T>(ActorActionAttrDef attrId, out T value)
        {
            return GetAtrributeValue((int) attrId, out value);
        }

        public bool GetAtrributeValue<T>(int attrId,out T val)
        {
            object objVal;
            var ret = m_dictAttr.TryGetValue(attrId, out objVal);
            if (ret)
            {
                val = (T) objVal;
            }
            else
            {
                val = default(T);
            }
            return ret;
        }

        public void RegAttrChangeEvent<T>(int attrId, Action<T, T> handler)
        {
            AttrChangeHandler handlerNode;
            if (!m_attrChangedListener.TryGetValue(attrId, out handlerNode))
            {
                handlerNode = new AttrChangeHandler();
                m_attrChangedListener[attrId] = handlerNode;
            }
            
            handlerNode.AddDelegate(handler);
        }

        public void UnRegAttrChangeEvent<T>(int attrId, Action<T, T> handler)
        {
            UnRegAttrChangeEvent(attrId,handler);
        }

        public void UnRegAttrChangeEvent(int attrId, Delegate handler)
        {
            AttrChangeHandler handlerNode;
            if (m_attrChangedListener.TryGetValue(attrId, out handlerNode))
            {
                handlerNode.RmvDelegate(handler);
            }
        }
    }
}